/**
 * 
 */
package wong.board.client.ui;

import java.util.Map;

import wong.board.client.util.JSONTool;
import wong.board.client.util.JSTool;
import wong.board.client.widgets.Button;
import wong.board.client.widgets.Button.ButtonCallback;
import wong.board.client.widgets.HasButtonCallbacks;
import wong.board.shared.ContentKeys;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONBoolean;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.HasText;
import com.google.gwt.user.client.ui.HasValue;

/**
 * @author wong
 * 
 */
public class DevelopmentPresenter extends Presenter<DevelopmentPresenter.View, JSONObject> {
	public static final String SAME_WINDOW_TARGET = "same_window";
	private ViewHandler handler;
	private JSONObject hostList;
	private JSONObject portList;
	private JSONArray pathsArray;
	private JSONObject windowFeatures;
	private String featuresString;

	public DevelopmentPresenter() {
		this((View) GWT.create(View.class));
	}

	public DevelopmentPresenter(View view) {
		super(view);
	}

	@Override
	protected void onViewAttached() {
		super.onViewAttached();
		handler = new ViewHandler();
		getView().getLaunchButtonsCallbacks().addCallback(handler);
	}

	@Override
	protected void onViewDetached() {
		getView().getLaunchButtonsCallbacks().removeCallback(handler);
		handler = null;
		super.onViewDetached();
	}

	@Override
	public void updateView(JSONObject development) {
		JSONBoolean newSameWindow = JSONTool.isBoolean(development, ContentKeys.DevelopmentSameWindow);
		if (newSameWindow != null) {
			getView().getSameWindow().setValue(Boolean.valueOf(newSameWindow.booleanValue()));
		}

		JSONObject newWindowFeatures = JSONTool.isObject(development, ContentKeys.DevelopmentWindowFeatures);
		if (newWindowFeatures != null) {
			if (windowFeatures == null) {
				windowFeatures = newWindowFeatures;
			} else {
				windowFeatures = JSONTool.merge(windowFeatures, newWindowFeatures, true);
			}
			// reset feature string
			featuresString = null;
		}

		String hostName = JSONTool.stringValue(development, ContentKeys.DevelopmentHostName);
		if (hostName != null) {
			if (hostName.isEmpty()) {
				hostName = Window.Location.getHostName();
			}
			getView().getHostName().setText(hostName);
		}

		JSONObject newHostList = JSONTool.isObject(development, ContentKeys.DevelopmentHostList);
		if (newHostList != null) {
			if (hostList == null) {
				hostList = newHostList;
			} else {
				hostList = JSONTool.merge(hostList, newHostList, false);
			}
			getView().setHostList(hostList);
		}

		String port = JSONTool.stringValue(development, ContentKeys.DevelopmentPort);
		if (port != null) {
			if (port.isEmpty()) {
				port = Window.Location.getPort();
			}
			getView().getPort().setText(port);
		}

		JSONObject newPortList = JSONTool.isObject(development, ContentKeys.DevelopmentPortList);
		if (newPortList != null) {
			if (portList == null) {
				portList = newPortList;
			} else {
				portList = JSONTool.merge(portList, newPortList, false);
			}
			getView().setPortList(portList);
		}

		JSONArray parametersArray = JSONTool.isArray(development, ContentKeys.DevelopmentParameters);
		if (parametersArray != null) {
			int parameterCount = parametersArray.size();
			for (int i = 0; i < parameterCount; i++) {
				JSONObject parameterData = parametersArray.get(i).isObject();
				String id = "p" + (i + 1);
				String name = JSONTool.stringValue(parameterData, ContentKeys.DevelopmentParameterName);
				String text = JSONTool.stringValue(parameterData, ContentKeys.DevelopmentParameterText);
				JSONNumber paramSize = JSONTool.isNumber(parameterData, ContentKeys.DevelopmentParameterSize);
				int size = paramSize == null ? 8 : Double.valueOf(paramSize.doubleValue()).intValue();
				JSONObject data = JSONTool.isObject(parameterData, ContentKeys.DevelopmentParameterList);
				getView().addParameter(id, name, text, size, data);
			}
		}

		JSONArray newPathsArray = JSONTool.isArray(development, ContentKeys.DevelopmentPaths);
		if (newPathsArray != null) {
			if (pathsArray == null) {
				pathsArray = newPathsArray;
			} else {
				pathsArray = JSONTool.merge(pathsArray, newPathsArray, true);
			}
			getView().resetButtons();
			int pathCount = pathsArray.size();
			for (int i = 0; i < pathCount; i++) {
				JSONArray pathData = pathsArray.get(i).isArray();
				getView().addButton(pathData);
			}
		}
	}

	protected void openWindow(String name, String path) {
		String url = getUrl(path);
		if (url == null) {
			Window.alert("Cannot open window:\nNo input for hostname.");
		} else {
			String parameters = getParametersString();
			if (parameters.length() > 0) {
				url = url + (path.indexOf("?") < 0 ? "?" : "&") + parameters;
			}

			String target = getView().getSameWindow().getValue().booleanValue() ? SAME_WINDOW_TARGET : name;
			if (featuresString == null) {
				featuresString = windowFeatures == null ? "" : JSONTool.toString(windowFeatures, ",", "=");
			}
			JSTool.openWindow(url, target, featuresString, true, true);
		}
	}

	private String getUrl(String path) {
		String url = null;
		String hostText = getView().getHostName().getText().trim();
		if (hostText.length() > 0) {
			String portText = getView().getPort().getText().trim();
			if (portText.length() > 0) {
				portText = ":" + portText;
			}

			url = getView().getUseHttps().getValue().booleanValue() ? "https" : "http";
			url = url + "://" + hostText + portText + "/" + path;
		}
		return url;
	}

	protected String getParametersString() {
		StringBuffer buffer = new StringBuffer();
		Map<String, String> parameters = getView().getSelectedParameters();
		String delimiter = "";
		for (String name : parameters.keySet()) {
			buffer.append(delimiter);
			String value = parameters.get(name);
			buffer.append(name + "=" + value);
			delimiter = "&";
		}
		return buffer.toString();
	}

	/*
	 * 
	 */

	private class ViewHandler implements ButtonCallback<JSONArray> {

		@Override
		public void onAction(Button<JSONArray> button, DomEvent<?> event) {
			JSONArray buttonData = button.getValue();
			String name = buttonData.get(0).isString().stringValue();
			String path = buttonData.get(1).isString().stringValue();
			openWindow(name, path);
		}

	}

	public interface View extends Presenter.View {

		HasValue<Boolean> getSameWindow();

		HasValue<Boolean> getUseHttps();

		HasText getHostName();

		void setHostList(JSONObject hostList);

		HasText getPort();

		void setPortList(JSONObject portList);

		void resetButtons();

		void addButton(JSONArray buttonData);

		void addParameter(String id, String name, String text, int size, JSONObject data);

		Map<String, String> getSelectedParameters();

		HasButtonCallbacks<JSONArray> getLaunchButtonsCallbacks();

	}

}
